#pragma once
#include <string>
#include "../common/message.hpp"
#include "../common/net.hpp"
#include <set>
namespace rpc
{
    namespace server
    {

        class PrividerMannager
        {
        public:
            using ptr = std::shared_ptr<PrividerMannager>;
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                std::mutex _mutex;
                Address _host;                     // 主机对应的地址
                std::vector<std::string> _methods; // 方法名称
                BaseConnection::ptr _conn;         // 服务提供者对应的连接信息
                Provider(const BaseConnection::ptr &conn, const Address &host)
                    : _host(host), _conn(conn)
                {
                }
                void AppendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.emplace_back(method);
                }
            };
            // 添加provider:根据连接添加
            Provider::ptr addProvider(const BaseConnection::ptr &conn, const Address &host, const std::string &method)
            {
                // 先查找是否有这个连接
                Provider::ptr provider;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it == _conns.end())
                    {
                        provider = std::make_shared<Provider>(conn, host);
                    }
                    else
                    {
                        provider = it->second;
                    }

                    auto &providers = _providers[method];
                    providers.insert(provider);

                }

                provider->AppendMethod(method);
                return provider;
            }
            // 根据连接得到对印的连接信息
            Provider::ptr getProvider(const BaseConnection::ptr &c)
            {
                auto it = _conns.find(c);
                if (it == _conns.end())
                {
                    errlog("连接未找到");
                    return Provider::ptr();
                }

                return it->second;
            }
            // 删除服务:还是使用连接来删除，连接找到对印的provides,然后遍历方法，shan
            void deldMethod(const BaseConnection::ptr &c)
            {
                auto it = _conns.find(c);
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    // 查看是否有该方法
                    if (it == _conns.end())
                    {
                        return;
                    }

                    // 遍历方法名称，根据服务提供者的方法信息中删除提供者
                    for (auto &method : it->second->_methods)
                    {
                        auto &provides = _providers[method];
                        provides.erase(it->second);
                    }
                    // 当前连接管理中删除
                    _conns.erase(it);
                }
            }

            std::vector<Address> getHosts(const std::string method)
            {
                auto it = _providers.find(method);
                if (it != _providers.end())
                {
                    std::vector<Address> hosts;
                    for (auto methods:it->second)
                    {
                        hosts.push_back(methods->_host);
                    }
                    return hosts;
                }

                return std::vector<Address>();
            }

        private:
            std::mutex _mutex;
            // 将方法名称与能够提供方法的provider管理起来
            std::unordered_map<std::string, std::set<Provider::ptr>> _providers;
            // 将连接和对应的provider管理起来
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;
        };

        class DiscoverManager
        {
        public:
            using ptr = std::shared_ptr<DiscoverManager>;
            struct Discover
            {
                using ptr = std::shared_ptr<Discover>;
                std::mutex _mutex;
                // 发现过的服务名称
                std::vector<std::string> _methods;
                // 服务对应的连接
                BaseConnection::ptr conn;
                Discover(const BaseConnection::ptr &c)
                    : conn(c)
                {
                }
                // 添加服务方法
                void AppendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.push_back(method);
                }
            };

            // 添加发现
            Discover::ptr addDiscover(const BaseConnection::ptr &c, const std::string &method)
            {
                Discover::ptr discover;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end())
                    {
                        discover = it->second;
                    }
                    else
                    {
                        discover = std::make_shared<Discover>(c);
                        // 将发现与连接管理起来
                        _conns.insert(std::make_pair(c, discover));
                    }

                    // 在方法名与数组的关联关系中添加上发现的服务
                    auto &discovers = _discovers[method];
                    discovers.insert(discover);
                }

                return discover;
            }
            // 删除发现
            void delDiscover(const BaseConnection::ptr &c)
            {
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it == _conns.end())
                    {
                        return;
                    }

                    for (auto method : it->second->_methods)
                    {
                        auto providers = _discovers[method];
                        providers.erase(it->second);
                    }

                    _conns.erase(it);
                }
            }
            // 服务上线通知
            void onlineNotify(const std::string &method, const Address host)
            {
                return Notify(method, host, SERVICE_TYPE::SERVICE_ONLINE);
            }
            // 服务下线通知
            void offlineNotify(const std::string &method, const Address host)
            {
                return Notify(method, host, SERVICE_TYPE::SERVICE_ONLINE);
            }

        private:
            void Notify(const std::string &method, const Address host, SERVICE_TYPE option)
            {
                // 找到服务的提供者
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _discovers.find(method);
                    if (it == _discovers.end())
                    {
                        return;
                    }

                    auto msg = MessageFactory::create<ServerRequest>();
                    // 找到了就向discovers里面的对象发送上线消息
                    msg->setId(UUID::uuid());
                    msg->setMethod(method);
                    msg->setOptionType(option);
                    msg->setHost(host);
                    msg->setMytype(MY_TYPE::REQ_SERVICE);
                    for (auto &discover : it->second)
                    {
                        discover->conn->send(msg);
                    }
                }
            }

        private:
            std::mutex _mutex;
            // 将方法名称与对应的discover管理起来
            std::unordered_map<std::string, std::set<Discover::ptr>> _discovers;
            // 将连接与对应的discover管理起来
            std::unordered_map<BaseConnection::ptr, Discover::ptr> _conns;
        };

        // 将上面两块整合起来
        class PDManager
        {
        public:
            using ptr = std::shared_ptr<PDManager>;
            PDManager()
                : _providers(std::make_shared<PrividerMannager>()),
                  _discovers(std::make_shared<DiscoverManager>()) {};
            // 询问服务是否再
            void onRequestServer(const BaseConnection::ptr &conn, const ServerRequest::ptr &request)
            {
                // 查看请求类型
                int option = request->getOption();
                // 服务注册，服务发现
                // 服务发现
                if (option == (int)SERVICE_TYPE::SERVICE_REGISTRY)
                {
                    // 新增服务提供者
                    _providers->addProvider(conn, request->getHost(), request->getMethod());
                    // 进行上线通知
                    _discovers->onlineNotify(request->getMethod(), request->getHost());
                    // 对服务进行响应
                    return registryResponse(conn, request);
                }
                else if (option == (int)SERVICE_TYPE::SERVICE_DISCOVERY)
                {
                    // 新增发现
                    _discovers->addDiscover(conn, request->getMethod());
                    return discoverResponse(conn, request);
                }
                else
                {
                    errlog("接收到消息，但是消息类型错误");
                    return errResponse(conn, request);
                }
            }
            // 关闭连接
            void connectionShutDown(const BaseConnection::ptr &conn)
            {
                // 获取服务提供者
                auto provider = _providers->getProvider(conn);
                if (provider.get() != nullptr)
                {
                    // 进行下线通知
                    for (auto method : provider->_methods)
                    {
                        _discovers->offlineNotify(method, provider->_host);
                    }
                    // 发现服务下线
                    _providers->deldMethod(conn);
                }
                _discovers->delDiscover(conn);
            }

        private:
            // 注册服务响应
            void registryResponse(const BaseConnection::ptr &conn, const ServerRequest::ptr &request)
            {
                auto resp = MessageFactory::create<ServerResponse>();
                resp->setId(request->getId());
                resp->setMethod(request->getMethod());
                resp->setMytype(MY_TYPE::RSP_SERVICE);
                resp->setOptype(SERVICE_TYPE::SERVICE_REGISTRY);
                resp->setRecode(MY_CODE::RCODE_OK);
                conn->send(resp);
            }
            // 发现服务响应
            void discoverResponse(const BaseConnection::ptr &conn, const ServerRequest::ptr &request)
            {
                auto resp = MessageFactory::create<ServerResponse>();
                resp->setId(request->getId());
                resp->setMytype(MY_TYPE::RSP_SERVICE);
                resp->setOptype(SERVICE_TYPE::SERVICE_DISCOVERY);
                // 要去获取conn对应的host数组
                std::vector<Address> hosts = _providers->getHosts(request->getMethod());
                if (hosts.empty())
                {
                    resp->setRecode(MY_CODE::RCODE_NOT_FOUND_SERVICE);
                    conn->send(resp);
                    return;
                }

                resp->setRecode(MY_CODE::RCODE_OK);
                resp->setHosts(hosts);
                resp->setMethod(resp->getMethod());
                conn->send(resp);
                return;
            }

            // 错误响应
            void errResponse(const BaseConnection::ptr &conn, const ServerRequest::ptr &request)
            {
                auto resp = MessageFactory::create<ServerResponse>();
                resp->setId(request->getId());
                resp->setMytype(MY_TYPE::RSP_SERVICE);
                resp->setRecode(MY_CODE::RCODE_INVAILED_OPTYPE);
                resp->setOptype(SERVICE_TYPE::SERVICE_UNKNOW);
                conn->send(resp);
            }

        private:
            PrividerMannager::ptr _providers;
            DiscoverManager::ptr _discovers;
        };
    }
}
